/**
 * 
 */
package ontology;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;

import javaclient3.structures.PlayerPose3d;
import javaclient3.structures.fiducial.PlayerFiducialItem;
import edu.stanford.smi.protege.model.KnowledgeBase;
import edu.stanford.smi.protege.model.Project;
import edu.stanford.smi.protege.server.RemoteProjectManager;
import edu.stanford.smi.protegex.owl.model.OWLIndividual;
import edu.stanford.smi.protegex.owl.model.OWLModel;
import edu.stanford.smi.protegex.owl.model.OWLNamedClass;
import edu.stanford.smi.protegex.owl.model.RDFIndividual;
import edu.stanford.smi.protegex.owl.model.RDFSClass;
import edu.stanford.smi.protegex.owl.model.RDFSLiteral;
import edu.stanford.smi.protegex.owl.model.RDFSNamedClass;
import edu.stanford.smi.protegex.owl.model.impl.DefaultOWLIndividual;

import java.awt.geom.Point2D;
import java.awt.geom.Point2D.Double;
import java.lang.Math;

import robot.MaterialObject;
import robot.PathPoint;

/**
 * @author bill
 *
 */
public class Ontology {
	RemoteProjectManager RPMInstance;
	Project project;
	KnowledgeBase kb;
	OWLModel model;
	
	public Ontology(String host, String username, String pasword, String nameProject) {
		connectProtege(host, username, pasword, nameProject);
	}

	private void connectProtege(String host, String username, String pasword, String nameProject) {
		//JenaOWLModel owlModel = null;
		//String uri = "file:///home/bill/Documents/Scolarité/TUM/S8+-+Diplomarbeit+ESG/Development/Awarerobot/Ontologies/Worldv3.owl";
		//String uri = "file:///home/bill/Documents/Worldv3.owl";
		
		//try {
		
		RPMInstance = RemoteProjectManager.getInstance();
		//owlModel = ProtegeOWL.createJenaOWLModelFromURI(uri);
		project = RPMInstance.getProject(host, username, pasword, nameProject, true);
		kb = project.getKnowledgeBase();
		model = (OWLModel) kb;
		//return model;
		
		//} catch (Exception e) {
			// TODO Auto-generated catch block
		//	System.out.println("Error!");
		//	e.printStackTrace();
		//}

	/*		Project p = null;
		try {
		    RemoteServer server = (RemoteServer) Naming.lookup("//localhost/" + Server.getBoundName());
		    if (server != null) {
		        RemoteSession session = server.openSession("Agent1", SystemUtilities.getMachineIpAddress(), "agent1");
		        if (session != null) {
		            RemoteServerProject serverProject = server.openProject("Awarerobot", session);
		            if (serverProject != null) {
		                p = RemoteClientProject.createProject(server, serverProject, session, true);
		            }
		        }
		    }
		} catch (Exception e) {
		    // Log.getLogger().severe(Log.toString(e));
			System.out.println("Error!");
			e.printStackTrace();
		}
	*/
	}



	public Project getProject() {
		return project;
	}



	public KnowledgeBase getKb() {
		return kb;
	}



	public OWLModel getModel() {
		return model;
	}

	public void actualizeObject(MaterialObject playerFiducialItem) {
		RDFSNamedClass goodClass = null;
		RDFSNamedClass nextGoodClass = model.getRDFSNamedClass("Object");
		float likelyness = 0;
		float bestLikelyness = 0;
		boolean objectExists = false;
		
		//System.out.println("start: object " + playerFiducialItem.toString());
		
		while (nextGoodClass != null) {
			goodClass = nextGoodClass;
			nextGoodClass = null;
			bestLikelyness = 0;

			for (Iterator itCandidate = goodClass.getSubclasses(false).iterator(); itCandidate.hasNext();) {
				RDFSNamedClass subCandidate = (RDFSNamedClass) itCandidate.next();
				for (Iterator itPattern = subCandidate.getInstances().iterator(); itPattern.hasNext();) {
					RDFIndividual instancePattern = (RDFIndividual) itPattern.next();
					if (instancePattern.hasRDFType(model.getRDFSNamedClass("Pattern_Element"))) {
						likelyness = Math.max(0, (1 - Math.abs(instancePattern.getPropertyValueLiteral(model.getRDFProperty("fiducial")).getFloat() - playerFiducialItem.getId())));
						if (likelyness > bestLikelyness) {
							bestLikelyness = likelyness;
							nextGoodClass = subCandidate;
						}
					}// else {
					//	System.out.println("defined by: " + ((DefaultOWLIndividual) instancePattern.getPropertyValue(model.getRDFProperty("defined_by"))).hasRDFType(model.getRDFSNamedClass("Mission")));
					//}
				}
			}			
		}
		//System.out.println("is a: " + goodClass.toString()); // + "fiducial: " + instancePattern.getPropertyValue(model.getRDFProperty("fiducial")).toString());

		Point2D.Double posObserved = new Point2D.Double(playerFiducialItem.getAbsPose().getPx(), playerFiducialItem.getAbsPose().getPy());

		for (Iterator itClass = goodClass.getInstances().iterator(); itClass.hasNext();) {
			DefaultOWLIndividual instanceCandidate = (DefaultOWLIndividual) itClass.next();
			if (instanceCandidate.hasRDFType(model.getRDFSNamedClass("Observed_Element"))) {
				Point2D.Double posCandidate = new Point2D.Double(
						((RDFIndividual) instanceCandidate.getPropertyValue(model.getRDFProperty("has_position"))).getPropertyValueLiteral(model.getRDFProperty("PosX")).getFloat(),
						((RDFIndividual) instanceCandidate.getPropertyValue(model.getRDFProperty("has_position"))).getPropertyValueLiteral(model.getRDFProperty("PosY")).getFloat());

				//if (instanceCandidate.getPropertyValueLiteral(model.getRDFProperty("hashcode")).getInt() == playerFiducialItem.hashCode()) {
				if (posObserved.distance(posCandidate) < 0.2) {
					objectExists = true;
					
					((RDFIndividual) instanceCandidate.getPropertyValue(model.getRDFProperty("has_position"))).setPropertyValue(model.getRDFProperty("PosX"), new Float(posObserved.getX()));
					((RDFIndividual) instanceCandidate.getPropertyValue(model.getRDFProperty("has_position"))).setPropertyValue(model.getRDFProperty("PosY"), new Float(posObserved.getY()));
				}
			}
		}
		
		if (!objectExists) {
			//System.out.println("Object doesn't exist, created");
			RDFIndividual newObject = goodClass.createRDFIndividual("LiveObject_" + playerFiducialItem.hashCode());
			newObject.addRDFType(model.getRDFSNamedClass("Observed_Element"));

			newObject.setPropertyValue(model.getRDFProperty("fiducial"), new Integer(playerFiducialItem.getId()));
			
			RDFIndividual newPosition = model.getRDFSNamedClass("Position").createRDFIndividual("Pos_" + playerFiducialItem.hashCode());
			newPosition.setPropertyValue(model.getRDFProperty("PosX"), new Float(posObserved.getX()));
			newPosition.setPropertyValue(model.getRDFProperty("PosY"), new Float(posObserved.getY()));
			newPosition.addRDFType(model.getRDFSNamedClass("Observed_Element"));
			newObject.setPropertyValue(model.getRDFProperty("has_position"), newPosition);
			
			System.out.println("created: " + "LiveObject_" + playerFiducialItem.hashCode());
		}

	}

	public ArrayList<PathPoint> getPathpoints(String movingObjectName) {
		ArrayList<PathPoint> pathpoints = new ArrayList<PathPoint>();
		OWLIndividual movingObject = model.getOWLIndividual(movingObjectName);
		OWLIndividual path = (OWLIndividual) movingObject.getPropertyValue(model.getRDFProperty("has_path"));
		
		for (Iterator itPathpoint = path.getPropertyValues(model.getRDFProperty("has_waypoint")).iterator(); itPathpoint.hasNext();) {
			OWLIndividual waypoint = (OWLIndividual) itPathpoint.next();
			OWLIndividual ontoPos = (OWLIndividual) waypoint.getPropertyValue(model.getRDFProperty("has_position"));
			
			PlayerPose3d position = new PlayerPose3d();
			position.setPx(ontoPos.getPropertyValueLiteral(model.getRDFProperty("PosX")).getFloat());
			position.setPy(ontoPos.getPropertyValueLiteral(model.getRDFProperty("PosY")).getFloat());
			
			int time = (int) waypoint.getPropertyValueLiteral(model.getRDFProperty("time")).getLong() * 1000;
			
			//time.parse(s) = new Date();
			
			PathPoint pathpoint = new PathPoint(position, time);
			pathpoints.add(pathpoint);
		}

		Collections.sort(pathpoints, new Comparator() {
			public int compare(Object op1, Object op2) {
				PathPoint p1 = (PathPoint) op1;
				PathPoint p2 = (PathPoint) op2;
				if (p1.getTime() < p2.getTime()) return -1;
				if (p1.getTime() > p2.getTime()) return 1;
				return 0;
				}
		});
		return pathpoints;
	}
}